<?php

namespace Zlf\Img\Captcha;

class ImgCaptcha
{
    /**
     * 默认配置
     * @var array
     */
    private $config = [
        'char_preset' => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', // 预设字符集，不支持多字节字符
        'length' => 4, // 验证码位数
        'width' => 120, // 图片宽
        'height' => 34, // 图片高
        'bg' => [243, 251, 254], // 背景颜色
        'use_noise' => true, // 是否添加杂点
    ];

    private $_code=[];

    /**
     * 验证码字体颜色
     * @var int[]
     */
    private $textColor = [];

    /**
     * 图片标识符
     * @var resource
     */
    private $im = null;

    /**
     * 图片宽
     * @var int
     */
    protected $imageWidth = 0;

    /**
     * 图片高
     * @var int
     */
    protected $imageHeight = 0;

    public static function instance($config = []): ImgCaptcha
    {
        return new self($config);
    }


    /**
     * ThinkCaptcha constructor.
     * @param array $config
     */
    public function __construct(array $config = [])
    {
        foreach ($config as $key => $val) {
            if (isset($this->config[$key])) {
                $this->config[$key] = $val;
            }
        }
    }


    public function getConfig(): array
    {
        return $this->config;
    }


    /**
     * 生成图片
     *
     * @return false|resource
     */
    public function create()
    {
        $this->_code = $this->generate();

        $this->imageWidth = $this->config['width'];
        $this->imageHeight = $this->config['height'];

        $font_size = intval($this->config['height'] * 0.66);


        // 图片宽(px)
        if (!$this->imageWidth) {
            $this->imageWidth = intval(ceil($this->config['length'] * $font_size + ($this->config['length'] + 1) * 10));
        }
        // 图片高(px)
        if (!$this->imageHeight) {
            $this->imageHeight = intval(ceil($font_size + 20));
        }

        // 建立一幅 $this->imageW x $this->imageH 的图像
        if (function_exists('imagecreatetruecolor')) {
            $this->im = imagecreatetruecolor((int)$this->imageWidth, (int)$this->imageHeight);
        } else {
            $this->im = imagecreate($this->imageWidth, $this->imageHeight);
        }

        // 背景色
        $background_color = imagecolorallocate($this->im, $this->config['bg'][0], $this->config['bg'][1], $this->config['bg'][2]);
        // 画一个方形并填背景色
        imagefill($this->im, 0, 0, $background_color);

        // 验证码字体随机颜色
        for ($i = 0; $i < $this->config['length']; $i++) {
            $this->textColor[] = imagecolorallocate($this->im, mt_rand(1, 150), mt_rand(1, 150), mt_rand(1, 150));
        }
        $fontttf = dirname(__DIR__) . '/assets/code-font.otf';
        if ($this->config['use_noise']) {
            // 绘杂点
            $this->writeNoise();
        }
        $texts = preg_split('//u', $this->_code, -1, PREG_SPLIT_NO_EMPTY); // 验证码
        $mx = intval(ceil(($this->imageWidth - $font_size * $this->config['length']) / ($this->config['length'] + 1)));
        $my = intval(ceil(($this->imageHeight - $font_size) / 2));
        $mx = $mx > 0 ? $mx : 0;
        $my = $my > 0 ? $my : 5; // 上边距为负数时，修改上边距随机最大数为5
        $x = $mx;
        $left = intval(($this->config['width'] / $this->config['length'] - $font_size) * 0.6);
        if ($left <= 0) {
            $left = 0;
        }
        foreach ($texts as $i => $char) {
            $y = intval(ceil(($font_size + mt_rand(0, $my))));
            $angle = mt_rand(-5, 5);
            imagettftext($this->im, $font_size, $angle, $x, $y, $this->textColor[$i], $fontttf, $char);
            if ($i === 0) {
                $x += intval($left * 0.5) + $font_size + mt_rand(0, $mx);
            } else {
                $x += $left + $font_size + mt_rand(0, $mx);
            }
        }
        return $this->im;
    }


    /**
     * base64输出验证码
     *
     * @return mixed
     */
    public function getCaptcha()
    {
        if (false === $this->create()) {
            return false;
        }
        ob_start();
        imagepng($this->im);
        $imgContent = ob_get_contents();
        ob_end_clean();
        imagedestroy($this->im);
        $this->im = null;
        return [
            'image' => 'data:image/png;base64,' . base64_encode($imgContent),
            'code' =>$this->_code
        ];
    }

    /**
     * 创建验证码
     * @return string char生成的验证码字符
     */
    private function generate(): string
    {
        $char = '';
        $characters = preg_split('//u', $this->config['char_preset'], -1, PREG_SPLIT_NO_EMPTY);
        for ($i = 0; $i < $this->config['length']; $i++) {
            $char .= $characters[mt_rand(0, count($characters) - 1)];
        }
        return $char;
    }


    /**
     * 画杂点
     * 往图片上写不同颜色的字母或数字
     */
    private function writeNoise(): void
    {
        $codeSet = '**************************************************';
        $m = intval(ceil($this->imageWidth / 20));
        for ($i = 0; $i < $m; $i++) {
            //杂点颜色
            $noiseColor = imagecolorallocate($this->im, mt_rand(150, 225), mt_rand(150, 225), mt_rand(150, 225));
            for ($j = 0; $j < 5; $j++) {
                // 绘杂点
                imagestring($this->im, mt_rand(1, 5), mt_rand(-10, $this->imageWidth), mt_rand(-10, $this->imageHeight), $codeSet[mt_rand(0, 29)], $noiseColor);
            }
        }
    }
}